﻿
using HalconDotNet;
using LeaderCCSLaserUI.Data.Common.Services;
using LeaderCCSLaserUI.Models;
using LeaderCCSLaserUI.Services;
using MotionRobot.Models;
using Newtonsoft.Json;
using NLog;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using LeaderCCSLaserUI.Data.Extensions;
using MvCamCtrl.NET.CameraParams;
using MvCamCtrl.NET;
using System.Collections.Concurrent;
using LeaderCCSLaserUI.Data;
using System.Linq;
using LeaderCCSLaserUI.Models.VisionModels;

namespace LeaderCCSLaserUI.ViewModels
{
    public class MainWindowViewModel: BindableBase
    {
        //
        #region 变量
        private readonly IRegionManager regionManager;

        private readonly IDialogService _dialogService;
        private readonly IDialogHostService _dialogHostService;

        private readonly IGTSCardService gTSCard;
        private readonly IPLCService pLC;
        private readonly IServoModbusService servoModbus;
        private readonly IEventAggregator aggregator;
        private readonly IHIKCameraService leftCamera;
        private readonly IHIKCameraService rightCamera;
        private static Logger logger = LogManager.GetCurrentClassLogger();
        private Param? systemParam;
        private CancellationTokenSource source1;
        private bool isAxisDialogShow = false, isPLCDialogShow = false, isWorkPointDialogShow = false, isBarcodeScanDialogShow = false, isParameterDialogShow = false, isCameraCalibDialogShow = false,
            isPartNumDialogShow = false, isVisionProgramDialogShow = false, isZControlDialogShow = false;
        private string leftEngineScriptFileName = string.Empty, rightEngineScriptFileName = string.Empty;
        #endregion
        #region 属性绑定
        public string Title { get; set; } = "LeaderCCSLaserUI";
        public string Version { get; set; } = "3.2.1";
        private string partNum;
        public string PartNum
        {
            get { return partNum; }
            set { SetProperty(ref partNum, value); }
        }
        private bool axisState;
        public bool AxisState
        {
            get { return axisState; }
            set { SetProperty(ref axisState, value); }
        }
        private bool pLCState;
        public bool PLCState
        {
            get { return pLCState; }
            set { SetProperty(ref pLCState, value); }
        }
        private bool leftCameraState;
        public bool LeftCameraState
        {
            get { return leftCameraState; }
            set { SetProperty(ref leftCameraState, value); }
        }
        private bool rightCameraState;
        public bool RightCameraState
        {
            get { return rightCameraState; }
            set { SetProperty(ref rightCameraState, value); }
        }
        private bool leftWeldScriptState;
        public bool LeftWeldScriptState
        {
            get { return leftWeldScriptState; }
            set { SetProperty(ref leftWeldScriptState, value); }
        }
        private bool rightWeldScriptState;
        public bool RightWeldScriptState
        {
            get { return rightWeldScriptState; }
            set { SetProperty(ref rightWeldScriptState, value); }
        }
        private bool monitorState;
        public bool MonitorState
        {
            get { return monitorState; }
            set { SetProperty(ref monitorState, value); }
        }
        #endregion
        #region 命令绑定
        private DelegateCommand appLoadedEventCommand;
        public DelegateCommand AppLoadedEventCommand =>
            appLoadedEventCommand ?? (appLoadedEventCommand = new DelegateCommand(ExecuteAppLoadedEventCommand));
        private DelegateCommand appClosedEventCommand;
        public DelegateCommand AppClosedEventCommand =>
            appClosedEventCommand ?? (appClosedEventCommand = new DelegateCommand(ExecuteAppClosedEventCommand));
        private DelegateCommand<object> menuCommand;
        public DelegateCommand<object> MenuCommand =>
            menuCommand ?? (menuCommand = new DelegateCommand<object>(ExecuteMenuCommand));

        void ExecuteMenuCommand(object obj)
        {
            switch (obj.ToString())
            {
                case "轴":
                    {
                        if (!isAxisDialogShow)
                        {
                            var result = _dialogHostService.Password("请输入密码");
                            if (result == ButtonResult.Yes)
                            {
                                isAxisDialogShow = true;
                                DialogParameters param = new DialogParameters();
                                //param.Add("PartNum", paramService.GetPart());
                                _dialogService.Show("AxisDialog", param, arg =>
                                {
                                    isAxisDialogShow = false;
                                });
                            }
                        }
                    }
                    break;
                case "PLC":
                    {
                        if (!isPLCDialogShow)
                        {
                            var result = _dialogHostService.Password("请输入密码");
                            if (result == ButtonResult.Yes)
                            {
                                isPLCDialogShow = true;
                                DialogParameters param = new DialogParameters();
                                //param.Add("PartNum", paramService.GetPart());
                                _dialogService.Show("PLCDialog", param, arg =>
                                {
                                    isPLCDialogShow = false;
                                });
                            }
                        }
                    }
                    break;
                case "扫码":
                    {
                        if (!isBarcodeScanDialogShow)
                        {
                            var result = _dialogHostService.Password("请输入密码");
                            if (result == ButtonResult.Yes)
                            {
                                isBarcodeScanDialogShow = true;
                                DialogParameters param = new DialogParameters();
                                //param.Add("PartNum", paramService.GetPart());
                                _dialogService.Show("BarcodeScanDialog", param, arg =>
                                {
                                    isBarcodeScanDialogShow = false;
                                });
                            }
                        }
                    }
                    break;
                case "工作点":
                    {
                        if (!isWorkPointDialogShow)
                        {
                            var result = _dialogHostService.Password("请输入密码");
                            if (result == ButtonResult.Yes)
                            {
                                isWorkPointDialogShow = true;
                                DialogParameters param = new DialogParameters();
                                //param.Add("PartNum", paramService.GetPart());
                                _dialogService.Show("WorkPointDialog", param, arg =>
                                {
                                    isWorkPointDialogShow = false;
                                });
                            }
                        }
                    }
                    break;
                case "机台参数":
                    {
                        if (!isParameterDialogShow)
                        {
                            var result = _dialogHostService.Password("请输入密码");
                            if (result == ButtonResult.Yes)
                            {
                                isParameterDialogShow = true;
                                DialogParameters param = new DialogParameters();
                                //param.Add("PartNum", paramService.GetPart());
                                _dialogService.Show("ParameterDialog", param, arg =>
                                {
                                    isParameterDialogShow = false;
                                });
                            }
                        }
                    }
                    break;
                //左标定
                case "左标定":
                    {
                        if (!isCameraCalibDialogShow)
                        {
                            var result = _dialogHostService.Password("请输入密码");
                            if (result == ButtonResult.Yes)
                            {
                                isCameraCalibDialogShow = true;
                                DialogParameters param = new DialogParameters();
                                param.Add("HandIndex", 0);
                                _dialogService.Show("CameraCalibDialog", param, arg =>
                                {
                                    isCameraCalibDialogShow = false;
                                });
                            }
                        }
                    }
                    break;
                //左算法
                //case "左算法":
                //    {
                //        if (!isCameraCalibDialogShow)
                //        {
                //            var result = _dialogHostService.Password("请输入密码");
                //            if (result == ButtonResult.Yes)
                //            {
                //                isCameraCalibDialogShow = true;
                //                DialogParameters param = new DialogParameters();
                //                param.Add("HandIndex", 0);
                //                _dialogService.Show("CameraVisionDialog", param, arg =>
                //                {
                //                    isCameraCalibDialogShow = false;
                //                });
                //            }
                //        }
                //    }
                //    break;

                //右标定
                case "右标定":
                    {
                        if (!isCameraCalibDialogShow)
                        {
                            var result = _dialogHostService.Password("请输入密码");
                            if (result == ButtonResult.Yes)
                            {
                                isCameraCalibDialogShow = true;
                                DialogParameters param = new DialogParameters();
                                param.Add("HandIndex", 1);
                                _dialogService.Show("CameraCalibDialog", param, arg =>
                                {
                                    isCameraCalibDialogShow = false;
                                });
                            }
                        }
                    }
                    break;
                //右算法
                //case "右算法":
                //    {
                //        if (!isCameraCalibDialogShow)
                //        {
                //            var result = _dialogHostService.Password("请输入密码");
                //            if (result == ButtonResult.Yes)
                //            {
                //                isCameraCalibDialogShow = true;
                //                DialogParameters param = new DialogParameters();
                //                param.Add("HandIndex", 1);
                //                _dialogService.Show("CameraVisionDialog", param, arg =>
                //                {
                //                    isCameraCalibDialogShow = false;
                //                });
                //            }
                //        }
                //    }
                //    break;

                case "料号":
                    if (!isPartNumDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            isPartNumDialogShow = true;
                            _dialogService.Show("PartNumDialog", arg =>
                            {
                                isPartNumDialogShow = false;
                            });
                        }
                    }
                    break;
                case "编程":
                    if (!isVisionProgramDialogShow)
                    {
                        isVisionProgramDialogShow = true;
                        DialogParameters param = new DialogParameters();
                        param.Add("PartNum", PartNum);
                        _dialogService.Show("VisionProgramDialog", param, arg =>
                        {
                            isVisionProgramDialogShow = false;
                        });
                    }
                    break;
                case "双铝巴管控":
                    if (!isZControlDialogShow)
                    {
                        var result = _dialogHostService.Password("请输入密码");
                        if (result == ButtonResult.Yes)
                        {
                            isZControlDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("PartNum", PartNum);
                            _dialogService.Show("ZControlDialog", param, arg =>
                            {
                                isZControlDialogShow = false;
                            });
                        }
                    }
                    break;
                default:
                    break;
            }
        }
        async void ExecuteAppClosedEventCommand()
        {
            aggregator.SendMessage("AppClose");
            if (source1 != null)
            {
                source1.Cancel();
            }
            GTSCard.AxisStop(gTSCard.A1, 1);
            GTSCard.AxisStop(gTSCard.A2, 1);
            GTSCard.AxisStop(gTSCard.A3, 1);
            GTSCard.AxisStop(gTSCard.A5, 1);
            GTSCard.AxisStop(gTSCard.A6, 1);
            GTSCard.AxisStop(gTSCard.A7, 1);
            GTSCard.ServoOff(gTSCard.A1);
            GTSCard.ServoOff(gTSCard.A2);
            GTSCard.ServoOff(gTSCard.A3);
            GTSCard.ServoOff(gTSCard.A5);
            GTSCard.ServoOff(gTSCard.A6);
            GTSCard.ServoOff(gTSCard.A7);
            GTSCard.SetDoPort1(gTSCard.A1.CardNo, 0xFFFF);
            if (pLC.Connected)
            {
                pLC.WriteYCoil(16, false);
                pLC.WriteYCoil(17, false);
                pLC.WriteYCoil(18, false);
                pLC.WriteYCoil(19, false);
            }
            leftCamera.CloseCamera();
            rightCamera.CloseCamera();
            await Task.Delay(200);
            servoModbus.Close();
            pLC.Close();
        }
        void ExecuteAppLoadedEventCommand()
        {

            aggregator.SendMessage($"PartNum;{systemParam.PartList[systemParam.PartIndex]}", "MES");

            bool gtsCardInitResult = gTSCard.Init(8, "Top_A8", "Top_A8");
            AxisState = gtsCardInitResult;
            if (!gtsCardInitResult)
            {
                logger.Error("轴卡初始化失败");
            }
            else
            {
                Task.Run(() => { 
                    var r = servoModbus.Connect(systemParam.ServoAbsCOM);
                    if (r)
                    {
                        try
                        {
                            {
                                int pls = servoModbus.ReadInovance(1);//读取Z1轴脉冲
                                GTSCard.AxisPosSet(gTSCard.A3, pls * gTSCard.A3.Equiv - systemParam.Z1Abs);
                                GTSCard.AxisEncSet(gTSCard.A3, pls * gTSCard.A3.Equiv - systemParam.Z1Abs);
                            }
                            {
                                int pls = servoModbus.ReadInovance(2);//读取Z2轴脉冲
                                GTSCard.AxisPosSet(gTSCard.A7, pls * gTSCard.A7.Equiv - systemParam.Z2Abs);
                                GTSCard.AxisEncSet(gTSCard.A7, pls * gTSCard.A7.Equiv - systemParam.Z2Abs);
                            }
                        }
                        catch (Exception ex)
                        {
                            logger.Error(ex);
                        }
                    }
                    else
                    {
                        logger.Error("伺服位置端口连接失败");
                    }
                });
            }

            Task.Run(() => { 
                var r = pLC.Connect(systemParam.PLC_IP);
                PLCState = r;
                if (!r)
                {
                    logger.Error("PLC连接失败");
                }
                else
                {
                    //读PLC
                    source1 = new CancellationTokenSource();
                    CancellationToken token = source1.Token;
                    Task.Run(() => PLCReadAction(token), token);
                }
            });


            Task.Run(() => {
                var r = leftCamera.OpenCamera(systemParam.LeftCameraIP);
                LeftCameraState = r;
                if (!r)
                {
                    logger.Error("左相机连接失败");
                }
                r = rightCamera.OpenCamera(systemParam.RightCameraIP);
                RightCameraState = r;
                if (!r)
                {
                    logger.Error("右相机连接失败");
                }
            });

            switch (systemParam.LazerDevIndex)
            {
                case 1:
                    {
                        LeftWeldScriptState = true;
                        RightWeldScriptState = true;
                    }
                    break;

                default:
                case 0:
                    {

                        Task.Run(() => {
                            var r = MFunc.LazerScript(systemParam.LeftWeldIP, "Connect") != string.Empty;
                            LeftWeldScriptState = r;
                            if (!r)
                            {
                                logger.Error("左激光脚本连接失败");
                            }
                        });
                        Task.Run(() => {
                            var r = MFunc.LazerScript(systemParam.RightWeldIP, "Connect") != string.Empty;
                            RightWeldScriptState = r;
                            if (!r)
                            {
                                logger.Error("右激光脚本连接失败");
                            }
                        });
                    }
                    break;
            }
            regionManager.Regions["WorkMapRegion"].RequestNavigate("WorkMapView");
            regionManager.Regions["LeftHandRegion"].RequestNavigate("Left");
            regionManager.Regions["RightHandRegion"].RequestNavigate("Right");
        }
        #endregion
        #region 构造函数
        void ImageCallbackFunc1(IntPtr pData, ref MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            if (leftCamera.m_bIsDeviceOpen)
            {
                //Debug.WriteLine("Get one frame: Width[" + Convert.ToString(pFrameInfo.nWidth) + "] , Height[" + Convert.ToString(pFrameInfo.nHeight)
                //    + "] , FrameNum[" + Convert.ToString(pFrameInfo.nFrameNum) + "]");
                //Debug.WriteLine($"enPixelType:{pFrameInfo.enPixelType}");
                if (pFrameInfo.enPixelType == MvGvspPixelType.PixelType_Gvsp_Mono8)
                {
                    HObject Hobj;
                    HOperatorSet.GenImage1Extern(out Hobj, "byte", pFrameInfo.nWidth, pFrameInfo.nHeight, pData, IntPtr.Zero);
                    leftCamera.ImageQueue.Enqueue(Hobj.Clone());

                }
            }
        }
        void ImageCallbackFunc2(IntPtr pData, ref MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            if (rightCamera.m_bIsDeviceOpen)
            {
                if (pFrameInfo.enPixelType == MvGvspPixelType.PixelType_Gvsp_Mono8)
                {
                    HObject Hobj;
                    HOperatorSet.GenImage1Extern(out Hobj, "byte", pFrameInfo.nWidth, pFrameInfo.nHeight, pData, IntPtr.Zero);
                    rightCamera.ImageQueue.Enqueue(Hobj.Clone());
                }
            }
        }
        public MainWindowViewModel(IRegionManager _regionManager, IContainerProvider containerProvider)
        {
            HOperatorSet.ResetObjDb(5000, 5000, 1);
            HOperatorSet.SetSystem("clip_region", "false");
            HOperatorSet.SetSystem("store_empty_region", "true");
            MFunc.FunDictionary.Add("PreProcessing", new VM_PreProcessing());
            MFunc.FunDictionary.Add("ShapeModel", new VM_FindShapeModel());
            MFunc.FunDictionary.Add("BlobCircle", new VM_BlobCircle());
            MFunc.FunDictionary.Add("BlobRectangle", new VM_BlobRectangle());
            MFunc.FunDictionary.Add("TwoLineIntersection", new VM_TwoLineIntersection());
            MFunc.FunDictionary.Add("NccModel", new VM_FindNccModel());
            NlogConfig();
            LoadParam();
            LoadParamFromDB();
            PartNum = systemParam.PartList[systemParam.PartIndex];
            regionManager = _regionManager;

            _dialogService = containerProvider.Resolve<IDialogService>();
            _dialogHostService = containerProvider.Resolve<IDialogHostService>();
            gTSCard = containerProvider.Resolve<IGTSCardService>("GTSCard");
            pLC = containerProvider.Resolve<IPLCService>("PLC");
            servoModbus = containerProvider.Resolve<IServoModbusService>("ServoModbus");
            aggregator = containerProvider.Resolve<IEventAggregator>();
            leftCamera = containerProvider.Resolve<IHIKCameraService>("LeftCamera");
            leftCamera.ImageQueue = new ConcurrentQueue<HObject>();
            leftCamera.ImageCallbackFunc = ImageCallbackFunc1;
            rightCamera = containerProvider.Resolve<IHIKCameraService>("RightCamera");
            rightCamera.ImageQueue = new ConcurrentQueue<HObject>();
            rightCamera.ImageCallbackFunc = ImageCallbackFunc2;
            aggregator.ResgiterMessage(arg => {
                switch (arg.Message)
                {
                    case "ReloadParam":
                        LoadParam();
                        LoadParamFromDB();
                        PartNum = systemParam.PartList[systemParam.PartIndex];                       
                        break;
                    default:
                        break;
                }
                if (arg.Message.Contains("Monitor"))
                {
                    var strs = arg.Message.Split(new char[] { ';' });
                    if (strs.Length == 2)
                    {
                        MonitorState = strs[1] == "True";
                    }
                }
            }, "Run");
        }
        #endregion
        #region 函数
        private void NlogConfig()
        {
            var config = new NLog.Config.LoggingConfiguration();

            // Targets where to log to: File and Console
            var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "${basedir}/logs/${shortdate}.log", Layout = "${longdate}|${level:uppercase=true}|${message}" };
            var logconsole = new NLog.Targets.ConsoleTarget("logconsole");

            // Rules for mapping loggers to targets            
            config.AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, logconsole);
            config.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, logfile);

            // Apply config           
            NLog.LogManager.Configuration = config;
        }
        void LoadParam()
        {
            try
            {
                //Json序列化，从文件读取
                string jsonString = File.ReadAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Param.json"));
                systemParam = JsonConvert.DeserializeObject<Param>(jsonString);
                //systemParam.LeftInit = new MPoint();
                //systemParam.LeftLineStart = new MPoint();
                //systemParam.LeftLineEnd = new MPoint();
                //systemParam.RightInit = new MPoint();
                //systemParam.RightLineStart = new MPoint();
                //systemParam.RightLineEnd = new MPoint();
                //jsonString = JsonConvert.SerializeObject(systemParam, Formatting.Indented);
                //File.WriteAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Param.json"), jsonString);
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
        }
        void LoadParamFromDB()
        {
            using var mdb = new MDbContext(systemParam.PartList[systemParam.PartIndex]);
            var _mParam = mdb.MParams.FirstOrDefault(m => m.Name == "EngineScriptFileName" && m.Hand == 0);
            if (_mParam != null)
            {
                leftEngineScriptFileName = _mParam.Value;
            }
            _mParam = mdb.MParams.FirstOrDefault(m => m.Name == "EngineScriptFileName" && m.Hand == 1);
            if (_mParam != null)
            {
                rightEngineScriptFileName = _mParam.Value;
            }
        }
        private void PLCReadAction(CancellationToken token)
        {
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    return;
                }
                try
                {
                    var coils = pLC.ReadXCoils(0, 48);
                    for (int i = 0; i < 48; i++)
                    {
                        pLC.XCoils_X0[i] = coils[i];
                    }
                    coils = pLC.ReadYCoils(16, 16);
                    for (int i = 0; i < 16; i++)
                    {
                        pLC.YCoils_Y20[i] = coils[i];
                    }
                }
                catch { }

                Thread.Sleep(200);
            }
        }
        #endregion
    }
}
